function momenyFormat(num) {
  num = Number(num);
  if (isNaN(num)) return "0.00";
  return num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,");
}
/**
 * 筛选数组中指定字段都不为空的对象
 * @param {Array} arr - 要筛选的数组
 * @param {Array} fields - 需要检查的字段列表
 * @returns {Array} 包含指定字段都不为空的对象的新数组
 * // 使用示例
const arr = [
    {
        comboName: "",
        saleNum: "",
        type: 2,
        typeList1: [],
        typeList2: new Array(36),
        typeList3: [],
        typeName: "午餐",
        unit: "",
        unitName: ""
    },
    {
        comboName: "TAOCAN1",
        saleNum: "22",
        type: 2,
        typeList1: [],
        typeList2: new Array(36),
        typeList3: [],
        typeName: "午餐",
        unit: "",
        unitName: ""
    }
];

// 筛选 comboName 和 saleNum 都不为空的对象
const result = filterNonEmptyFields(arr, ['comboName', 'saleNum']);
console.log(result); 
// 输出：[{ comboName: "TAOCAN1", saleNum: "22", ... }]
// 只返回第二个对象，因为它的两个字段都有值
 */
function filterNonEmptyFields(arr, fields) {
  // 检查输入是否有效
  if (!Array.isArray(arr) || !Array.isArray(fields) || fields.length === 0) {
    return [];
  }

  // 筛选出指定字段全部不为空的对象
  return arr.filter((item) => {
    // 检查当前对象的所有指定字段是否都不为空
    return fields.every((field) => {
      // 字段不存在视为空
      if (!Object.prototype.hasOwnProperty.call(item, field)) {
        return false;
      }
      const value = item[field];
      // 不为空的条件：不是空字符串、不是null、不是undefined
      return value !== "" && value !== null && value !== undefined;
    });
  });
}
// 对象数组去重
function uniqueMultiPropertyArray(arr) {
  const uniqueArr = arr.filter((item, index, self) => {
    return (
      index ===
      self.findIndex(
        (obj) => obj.Id === item.Id && obj.cCusName === item.cCusName
      )
    );
  });

  return uniqueArr;
}
/**
 * 验证数组及其对象字段是否符合条件
 * @param {Array} arr - 需要验证的数组
 * @param {string|string[]} requiredFields - 必须存在且非空的字段名或字段名数组
 * @param {string|string[]} [nonEmptyObjectFields=[]] - 必须为非空对象的字段名或字段名数组
 * @param {boolean} [strictEmpty=true] - 是否严格检查空值（包括0、false等有意义的值）
 * @returns {boolean} - 所有条件满足返回true，否则返回false
 
 
 // 示例用法
 const listItem = [
   {
     comboCode: "",      // 空
     foodCode: "CP250724968",
     foodDish: {},       // 空对象
     foodId: 126,
     foodName: "",       // 空
     type: "2",
     typeName: "配菜"
   },
   {
     comboCode: "",      // 空
     foodCode: "CP250724968",
     foodDish: {},       // 空对象
     foodId: 126,
     foodName: "",       // 空
     type: "2",
     typeName: "配菜"
   }
 ];
 
 // 验证foodCode和type字段非空
 console.log(validateArray(listItem, ["foodCode", "type"])); // true
 
 // 验证foodCode和foodName字段非空（foodName为空，返回false）
 console.log(validateArray(listItem, ["foodCode", "foodName"])); // false
 
 // 验证foodDish是否为非空对象（foodDish是空对象，返回false）
 console.log(validateArray(listItem, ["foodCode"], ["foodDish"])); // false
 
 // 宽松模式：0不视为空
 console.log(validateArray([{ count: 0 }], "count", [], false)); // true
 */

function validateArrayFields(
  arr,
  requiredFields,
  nonEmptyObjectFields = [],
  strictEmpty = true
) {
  // 检查数组是否存在或为空
  if (!arr || arr.length === 0) {
    return false;
  }

  // 将单个字段名转换为数组
  const requiredList = Array.isArray(requiredFields)
    ? requiredFields
    : [requiredFields];
  const nonEmptyObjList = Array.isArray(nonEmptyObjectFields)
    ? nonEmptyObjectFields
    : [nonEmptyObjectFields];

  // 遍历数组中的每个对象
  for (const obj of arr) {
    // 检查必需字段是否存在且非空
    for (const field of requiredList) {
      const value = obj[field];

      // 判断字段是否为空
      const isEmpty = strictEmpty
        ? !value // 严格模式：0、false、''、null、undefined等都视为空
        : value === undefined || value === null || value === ""; // 宽松模式：只检查常见空值

      if (isEmpty) {
        return false; // 任何必需字段为空，验证失败
      }
    }

    // 检查特定字段是否为非空对象
    for (const field of nonEmptyObjList) {
      const value = obj[field];

      // 判断是否为非空对象
      const isValidObject =
        typeof value === "object" &&
        value !== null &&
        !Array.isArray(value) &&
        Object.keys(value).length > 0;

      if (!isValidObject) {
        return false; // 任何对象字段不是非空对象，验证失败
      }
    }
  }

  // 所有条件满足
  return true;
}

/**
let fieldsToCheck = ['comboName','saleNum'];
let result = checkFieldsAndGetIndices(list, fieldsToCheck);
console.log(result);
// 判断数组中每个对象元素里的某一个字段或者某几个字段是否为空，只要有任何一个对象里
的某一个字段或者某几个字段为空就不行，并且返回所有为空的数组下标  */
function checkFieldsAndGetIndices(arr, fields) {
  let emptyIndices = [];
  arr.forEach((obj, index) => {
    let isEmpty = fields.some((field) => {
      const value = obj[field];
      return value === null || value === undefined || value === "";
    });
    if (isEmpty) {
      emptyIndices.push(index);
    }
  });
  return emptyIndices;
}
/**
 * 判断当前时间是否在每周二00:00至周五12:00之间
 * @param {Date} [date] - 可选参数，指定要检查的日期，默认使用当前时间
 * @returns {boolean} - 如果在范围内返回true，否则返回false
 * 
// 使用示例
// console.log("当前是否在范围内：", isInTimeRange());
 */
function isInTimeRange(date) {
  // 使用提供的日期或当前日期
  const currentDate = date ? new Date(date) : new Date();

  // 获取星期几（0=星期日, 1=星期一, ..., 2=星期二, ..., 5=星期五）
  const day = currentDate.getDay();
  // 获取小时数（0-23）
  const hours = currentDate.getHours();
  // 获取分钟数（0-59）
  const minutes = currentDate.getMinutes();
  // 获取秒数（0-59）
  const seconds = currentDate.getSeconds();

  // 周二、周三、周四全天都在范围内
  if (day === 2 || day === 3 || day === 4) {
    return true;
  }

  // 处理周五的情况：仅00:00:00到12:00:00之间
  if (day === 5) {
    // 小时小于12 → 在范围内
    if (hours < 12) {
      return true;
    }
    // 刚好12:00:00也视为在范围内
    if (hours === 12 && minutes === 0 && seconds === 0) {
      return true;
    }
  }

  // 其他情况（周日、周一、周五12:00之后）均不在范围内
  return false;
}
/**
 * 将形如"2025/7/31"的日期格式化为"2025-07-31"格式
 * @param {string} dateString - 输入的日期字符串，格式为YYYY/M/D
 * @returns {string} 格式化后的日期字符串，格式为YYYY-MM-DD
 * // 使用示例
const originalDate = "2025/7/31";
const formattedDate = formatDate(originalDate);
console.log(formattedDate); // 输出: "2025-07-31"
 */
function formatDate(dateString) {
  // 分割日期字符串为年、月、日
  const [year, month, day] = dateString.split("/").map(Number);

  // 确保月份和日期为两位数（不足两位前面补0）
  const formattedMonth = String(month).padStart(2, "0");
  const formattedDay = String(day).padStart(2, "0");

  // 拼接成目标格式
  return `${year}-${formattedMonth}-${formattedDay}`;
}

/**
 * 验证值是否符合指定规则
 * @param {string|number} value - 需要验证的值
 * @param {Object} options - 验证选项配置
 * @param {boolean} [options.allowDecimal=false] - 是否允许小数点
 * @param {number|null} [options.maxLength=null] - 最大允许长度，null表示不限制
 * @param {boolean} [options.allowLetters=false] - 是否允许大小写字母
 * @param {boolean} [options.allowSpecialChars=false] - 是否允许特殊符号
 * @param {boolean} [options.allowChinese=false] - 是否允许汉字
 * @param {boolean} [options.allowZero=true] - 是否允许值为0
 * @returns {Object} 包含验证结果和错误信息的对象
 * 
// 示例用法
const testCases = [
    { 
        value: 0, 
        config: { allowZero: false } 
    },
    { 
        value: "0", 
        config: { allowZero: false }  
    },
    { 
        value: "123.45", 
        config: { allowDecimal: true, maxLength: 10 } 
    },
    { 
        value: "Hello123", 
        config: { allowLetters: true } 
    },
    { 
        value: "测试文字", 
        config: { allowChinese: true } 
    },
    { 
        value: "user@12.", 
        config: { allowDecimal:true,allowLetters: true, allowSpecialChars: true } 
    },
    { 
        value: "123456", 
        config: { maxLength: 5 } 
    }
];

// 执行测试
testCases.forEach(({ value, config }, index) => {
    const result = validateValue(value, config);
    console.log(`测试用例 ${index + 1}:`);
    console.log(`值: ${typeof value}类型的"${value}"`);
    console.log(`配置:`, config);
    console.log(`结果:`, result);
    console.log('---');
});
 */
function validateValue(value, options = {}) {
  // 处理原始值，转为字符串便于统一处理
  const originalValue = value;
  const inputStr = String(value);

  // 设置默认选项，新增allowNegative默认值为false
  const {
    allowDecimal = false,
    maxLength = null,
    allowLetters = false,
    allowSpecialChars = false,
    allowChinese = false,
    allowZero = true,
    allowNegative = false, // 新增选项：是否允许负数
  } = options;

  // 检查空值  暂时注释
  // if (inputStr.trim() === '') {
  // 	return {
  // 		valid: false,
  // 		message: '值不能为空'
  // 	};
  // }
  // 检查负数（仅允许开头出现一个减号）
  if (inputStr.includes("-")) {
    // 如果不允许负数，直接返回错误
    if (!allowNegative) {
      return {
        valid: false,
        message: "不允许输入负数",
      };
    }
    // 检查减号是否只出现在开头且只出现一次
    if (inputStr.indexOf("-") !== 0 || inputStr.lastIndexOf("-") !== 0) {
      return {
        valid: false,
        message: "负数格式不正确，减号只能出现在开头且只能有一个",
      };
    }
  }

  // 检查是否为0（包括字符串"0"和数字0）
  if (!allowZero && (originalValue === 0 || inputStr === "0")) {
    return {
      valid: false,
      message: "不允许值为0",
    };
  }
  // 检查前导零（整数部分）
  const integerPart = inputStr.split(".")[0];
  if (integerPart.length > 1 && integerPart.startsWith("0")) {
    return {
      valid: false,
      message: "输入不能包含前导0",
    };
  }

  // 检查长度限制
  if (maxLength !== null && inputStr.length > maxLength) {
    return {
      valid: false,
      message: `长度不能超过${maxLength}个字符`,
    };
  }

  // 定义各类字符的正则表达式
  const regexPatterns = {
    decimal: /\./,
    letter: /[a-zA-Z]/,
    chinese: /[\u4e00-\u9fa5]/,
    // 包含常见特殊符号，可根据需要调整
    specialChar: /[!@#$%^&*(),.?":{}|<>;'/\\[\]`~=+\_\s]/,
    digit: /[0-9]/,
  };

  // 检查每个字符
  for (const char of inputStr) {
    // 数字默认允许（0的整体判断已在前面处理）
    if (regexPatterns.digit.test(char)) {
      continue;
    }

    // 检查小数点
    if (regexPatterns.decimal.test(char)) {
      if (!allowDecimal) {
        return {
          valid: false,
          message: "不允许包含小数点",
        };
      }
      continue;
    }

    // 检查字母
    if (regexPatterns.letter.test(char)) {
      if (!allowLetters) {
        return {
          valid: false,
          message: "不允许包含字母",
        };
      }
      continue;
    }

    // 检查汉字
    if (regexPatterns.chinese.test(char)) {
      if (!allowChinese) {
        return {
          valid: false,
          message: "不允许包含汉字",
        };
      }
      continue;
    }

    // 检查特殊符号
    if (regexPatterns.specialChar.test(char)) {
      if (!allowSpecialChars) {
        return {
          valid: false,
          message: `不允许包含特殊符号: ${char}`,
        };
      }
      continue;
    }

    // 未识别的字符
    if (!allowNegative)
      return {
        valid: false,
        message: `不允许包含字符: ${char}`,
      };
  }

  return {
    valid: true,
    message: "验证通过",
  };
}
// 封装函数：返回指定位数的字符串
// 参数：str-原始字符串，length-指定的长度
// 功能：如果原字符串长度小于指定长度，补空格；如果大于，截断
// 使用示例
// console.log(getSpecifiedLengthString("hello", 10)); // "hello     "
// console.log(getSpecifiedLengthString("hello world", 5)); // "hello"
// console.log(getSpecifiedLengthString("test", 4)); // "test"
function getSpecifiedLengthString(str, length) {
  // 检查输入是否为字符串
  if (typeof str !== "string") {
    throw new Error("第一个参数必须是字符串");
  }

  // 检查长度是否为正整数
  if (typeof length !== "number" || length <= 0 || !Number.isInteger(length)) {
    throw new Error("第二个参数必须是正整数");
  }

  // 如果字符串长度小于指定长度，补空格
  if (str.length < length) {
    return str.padEnd(length, " ");
  }
  // 如果字符串长度大于等于指定长度，截断
  else {
    return str.substring(0, length);
  }
}

/**
 * 验证字段是否为空 * @param {string} value - 需要验证的值
 * @param {string} value - 传入的值
 * @param {string} fieldName - 传入的字段名
 *
 */
function checkEmpty(value, fieldName) {
  // 处理空值情况：null、undefined、空字符串（含仅空格的字符串）
  const isEmpty =
    value === null || value === undefined || String(value).trim() === "";

  if (isEmpty) {
    return {
      isEmpty: false,
      message: `请输入${fieldName}`,
    };
  }

  return {
    isEmpty: true,
    message: "",
  };
}

/**
 * 验证手机号、邮箱、银行卡号或联行号格式 * @param {string} value - 需要验证的值
 * @param {string} type - 验证类型：'phone'|'email'|'bankCard'|'bankBranch'
 * @returns {Object} 验证结果
 *   - isValid: boolean - 是否通过验证
 *   - error: string - 错误信息（空字符串表示无错误）
 * @throws {Error} 当类型参数无效时抛出错误
 * // 使用示例
console.log(validateFormat('13800138000', 'phone'));
// { isValid: true, error: "" }

console.log(validateFormat('test@example.com', 'email'));
// { isValid: true, error: "" }

console.log(validateFormat('6222021234567890123', 'bankCard'));
// { isValid: true, error: "" }

console.log(validateFormat('102100099999', 'bankBranch'));
// { isValid: true, error: "" }

// 无效案例
console.log(validateFormat('1234567890', 'phone'));
// { isValid: false, error: "请输入有效的手机号（11位数字，以1开头）" }

console.log(validateFormat('invalid-email', 'email'));
// { isValid: false, error: "请输入有效的邮箱地址（如：example@domain.com）" }

console.log(validateFormat('123456', 'bankCard'));
// { isValid: false, error: "请输入有效的银行卡号（16-19位数字）" }
 */
function validateFormat(value, type) {
  // 处理空值情况
  const strValue = String(value).trim();
  // if (strValue === '' || value === null || value === undefined) {
  //     return {
  //         isValid: false,
  //         error: '输入不能为空'
  //     };
  // }

  // 定义验证规则映射表
  const validators = {
    // 手机号验证：中国大陆手机号，11位数字，以1开头，第二位为3-9
    phone: {
      regex: /^1[3-9]\d{9}$/,
      error: "请输入有效的手机号（11位数字，以1开头）",
    },
    // 邮箱验证：支持字母、数字、特殊字符及多级域名
    email: {
      regex: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
      error: "请输入有效的邮箱地址（如：example@domain.com）",
    },
    // 银行卡号验证：16-19位数字（涵盖大多数银行的卡号长度）
    supplierBankNumber: {
      regex: /^\d{16,19}$/,
      error: "请输入有效的银行卡号（16-19位数字）",
    },
    // 联行号验证：12位数字（银行联行号固定长度）
    supplierInterBank: {
      regex: /^\d{12}$/,
      error: "请输入有效的联行号（12位数字）",
    },
    // 统一社会信用代码验证：18位，包含数字、大写字母
    supplierCode: {
      regex: /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/,
      error: "请输入有效的统一社会信用代码（18位字符，含数字和大写字母）",
    },
  };

  // 验证类型是否有效
  if (!validators.hasOwnProperty(type)) {
    throw new Error(
      "无效的验证类型，可选类型：phone、email、bankCard、bankBranch"
    );
  }

  // 执行验证
  const { regex, error } = validators[type];
  if (regex.test(strValue)) {
    return {
      isValid: true,
      error: "",
    };
  } else {
    return {
      isValid: false,
      error,
    };
  }
}

/**
 * 根据传入的日期判断是星期几
 * @param {Date|string|number} date - 日期，可以是Date对象、日期字符串或时间戳
 * @returns {Object} 包含星期几数字和名称的对象
 * // 示例用法
const testDates = [
    new Date(),                  // 当前日期
    '2023-10-01',                // 字符串日期（国庆节）
    '2024-02-10',                // 字符串日期
    1710000000000,               // 时间戳
    'invalid-date',              // 无效日期
    999999999999999999999        // 无效时间戳
];

// 测试并输出结果
testDates.forEach((date, index) => {
    const result = getDayOfWeek(date);
    console.log(`测试用例 ${index + 1}:`);
    console.log(`输入:`, date);
    console.log(`结果:`, result);
    console.log('---');
});
 */
function getDayOfWeek(date) {
  // 处理不同类型的日期输入
  let targetDate;

  if (date instanceof Date) {
    // 如果是Date对象，直接使用
    targetDate = date;
  } else if (typeof date === "string" || typeof date === "number") {
    // 如果是字符串或数字，尝试转换为Date对象
    targetDate = new Date(date);
  } else {
    return {
      success: false,
      error: "无效的日期格式，请传入Date对象、日期字符串或时间戳",
    };
  }

  // 检查日期是否有效
  if (isNaN(targetDate.getTime())) {
    return {
      success: false,
      error: "无法解析为有效的日期",
    };
  }

  // 获取星期几（0表示星期日，6表示星期六）
  const dayNumber = targetDate.getDay();

  // 星期名称映射表
  const dayNames = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];

  return {
    success: true,
    dayNumber: dayNumber, // 数字形式（0-6）
    dayName: dayNames[dayNumber], // 中文名称
    date: targetDate.toLocaleDateString(), // 格式化的日期字符串
  };
}

function mergeArrays(arr1, key1, insertKey, arr2, key2) {
  // 遍历数组2中的每个元素
  return arr2.map((item2) => {
    // 在数组1中查找符合条件的元素（key1值与key2值相等）
    const matchedItem = arr1.find((item1) => item1[key1] === item2[key2]);
    // 如果找到匹配元素，将数组1的insertKey字段插入数组2的元素中
    if (matchedItem) {
      return {
        ...item2,
        [insertKey]: matchedItem[insertKey],
      };
    }
    // 未找到匹配元素则返回原元素
    return item2;
  });
}
function isEmptyObject(obj) {
  return (
    typeof obj === "object" && obj !== null && JSON.stringify(obj) === "{}"
  );
}

/**
 * 根据index字段查找菜单对象，若有children则合并子项属性到主对象
 * @param {Array} menuItems - 菜单数组
 * @param {string} targetIndex - 要查找的index值
 * @returns {Object|null} 处理后的菜单对象或null
 */
function findAndMergeMenuItem(menuItems, targetIndex) {
  // 检查输入是否为有效的数组
  if (!Array.isArray(menuItems)) {
    console.error("menuItems必须是一个数组");
    return null;
  }

  // 递归查找函数
  function search(items) {
    for (const item of items) {
      // 找到匹配的index
      if (item.index === targetIndex) {
        // 复制对象以避免修改原数据
        const result = { ...item };

        // 如果有children字段且是数组
        if (
          result.children &&
          Array.isArray(result.children) &&
          result.children.length > 0
        ) {
          // 合并第一个子项的属性（如果有多个子项，这里只合并第一个）
          const firstChild = result.children[0];
          Object.keys(firstChild).forEach((key) => {
            // 只合并主对象中不存在的属性
            if (!(key in result)) {
              result[key] = firstChild[key];
            }
          });

          // 移除children属性
          delete result.children;
        }

        return result;
      }

      // 如果有children，递归查找子菜单
      if (item.children && Array.isArray(item.children)) {
        const found = search(item.children);
        if (found) {
          return found;
        }
      }
    }
    return null;
  }

  return search(menuItems);
}
  /**
   * 深度克隆
   *
   * @param {Object} obj 传入需要克隆的对象
   * @returns {Object} 返回克隆好的对象
   */
  function deepClone(obj) {
    let result
    let objClass = this.getObjClass(obj)

    if (objClass === 'Object') {
      result = {}
    } else if (objClass === 'Array') {
      result = []
    } else {
      return obj // 如果是其他数据类型不复制，直接将数据返回
    }

    // 遍历目标对象
    for (let key in obj) {
      let value = obj[key]
      result[key] = this.deepClone(value)
    }

    return result
  }
 /**
   * 循环对象
   *
   * @param {Object|Array} obj 传入的值
   * @param {Function} fn 为每个项调用的回调
   */
 function forEach(obj, fn) {
  if (obj === null || typeof obj === 'undefined') return

  // 如果还没有可写的东西，就强制一个数组
  if (typeof obj !== 'object') obj = [obj]

  if (this.isArray(obj)) {
    // 数组循环
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj)
    }
  } else {
    // 对象循环
    for (var key in obj) {
      /* 是否具有键 */
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj)
      }
    }
  }
}

module.exports = {
  momenyFormat,
  uniqueMultiPropertyArray,
  validateArrayFields,
  checkFieldsAndGetIndices,
  isInTimeRange,
  formatDate,
  filterNonEmptyFields,
  validateFormat,
  validateValue,
  getDayOfWeek,
  mergeArrays,
  getSpecifiedLengthString,
  checkEmpty,
  isEmptyObject,
  findAndMergeMenuItem,
  deepClone,
  forEach,
};
